package org.jeecg.modules.fund.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Dict;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.fund.entity.FundList;
import org.jeecg.modules.fund.entity.FundMoving;
import org.jeecg.modules.fund.entity.FundVal;
import org.jeecg.modules.fund.mapper.FundValMapper;
import org.jeecg.modules.fund.model.FundValLineModel;
import org.jeecg.modules.fund.service.IFundListService;
import org.jeecg.modules.fund.service.IFundMovingService;
import org.jeecg.modules.fund.service.IFundValService;
import org.jeecg.modules.fund.util.FundDataUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

@Deprecated
@Slf4j
@Service
public class FundValServiceImpl extends ServiceImpl<FundValMapper, FundVal> implements IFundValService {
    @Autowired
    private IFundMovingService fundMovingService;
    @Autowired
    private IFundListService fundListService;

    @Override
    public void updateVal(String code, boolean updateAll) {
        FundList fund = fundListService.getOne(new LambdaQueryWrapper<FundList>().eq(FundList::getCode, code));
        if (fund == null) {
            return;
        }
        // 输入基金代码，获取数据
        JSONObject oj = FundDataUtil.getFundValueList(code);

        JSONArray upArr = new JSONArray();
        // 判断是否更新所有数据
        if (oj != null && !oj.getJSONArray("list").isEmpty()) {
            if (updateAll) {
                upArr = oj.getJSONArray("list");
            } else {
                JSONArray arr = oj.getJSONArray("list");
                upArr.add(arr.get(arr.size() - 1));
            }
        }
        // 更新基金收益率数据
        fundListService.updateById(new FundList()
                .setId(fund.getId())
                .setSylOn(oj.getBigDecimal("syl_1n"))
                .setSylSy(oj.getBigDecimal("syl_6y"))
                .setSylTy(oj.getBigDecimal("syl_3y"))
                .setSylOy(oj.getBigDecimal("syl_1y")));
        // 遍历出来数据
        upArr.forEach(obj -> {
            // 格式化数据
            JSONObject object = JSONObject.parseObject(obj.toString());
            // 构造净值实体
            FundVal fundVal = new FundVal();
            // 净值日期
            fundVal.setValDate(FundDataUtil.formatDate(object.getString("x")));
            // 所属基金
            fundVal.setFundId(fund.getId());
            // 单位净值
            fundVal.setNowVal(object.getBigDecimal("y"));
            // 日增长率
            fundVal.setValRate(object.getBigDecimal("equityReturn"));
            // 非估算值
            fundVal.setIsEstimate(0);
            // 更新主表数据
            fundListService.updateById(new FundList()
                    .setId(fund.getId())
                    .setNowVal(object.getBigDecimal("y"))
                    .setValDate(FundDataUtil.formatDate(object.getString("x")))
                    .setNowRate(object.getBigDecimal("equityReturn")));

            // 判断净值是否已经存在，如果存在则跳过
            FundVal entity = baseMapper.selectOne(new LambdaQueryWrapper<FundVal>()
                    .eq(FundVal::getFundId, fund.getId())
                    .eq(FundVal::getValDate, fundVal.getValDate()));
            if (entity != null) {
                baseMapper.deleteById(entity.getId());
            }

            // log.info("允许新增");
            // 说明数据是空的，可以新增
            baseMapper.insert(fundVal);
            // 生成趋势线
            create(fundVal.getValDate(), "10", fundVal.getFundId());
            create(fundVal.getValDate(), "26", fundVal.getFundId());
            create(fundVal.getValDate(), "60", fundVal.getFundId());
            create(fundVal.getValDate(), "250", fundVal.getFundId());
        });
    }

    @Override
    public void create(Date date, String type, String fundId) {
        try {
            // 查询数据
            Map<String, Object> map = this.getMap(new QueryWrapper<FundVal>()
                    .select("SUM(now_val) as 'val',count(*) as 'tot'")
                    .lambda()
                    .eq(FundVal::getFundId, fundId)
                    .le(FundVal::getValRate, date)
                    .ge(FundVal::getValDate, DateUtil.offsetDay(date, -(Integer.parseInt(type) - 1))));

            if (map != null) {
                // 获取合并值
                BigDecimal val = (BigDecimal) map.get("val");
                // 构造实体
                FundMoving entity = new FundMoving();
                entity.setType(type);
                entity.setValDate(date);
                // 计算趋势值
                BigDecimal mo = val.divide(new BigDecimal(map.get("tot").toString()), RoundingMode.FLOOR);
                entity.setValMoving(mo);
                entity.setFundId(fundId);
                // 查询数据是否存在
                FundMoving moving = fundMovingService.getOne(new LambdaQueryWrapper<FundMoving>()
                        .eq(FundMoving::getType, type)
                        .eq(FundMoving::getFundId, fundId)
                        .eq(FundMoving::getValDate, date));

                if (moving != null) {
                    entity.setId(moving.getId());
                }

                fundMovingService.saveOrUpdate(entity);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public List<Dict> createWave(String code) {
        // 构造参数
        FundValLineModel model = new FundValLineModel();
        model.setCode(code);
        // model.setStartDate("2024-04-08");
        model.setEndDate(DateUtil.now());

        // 获取列表数据
        List<Map<String, Object>> mapList = this.baseMapper.getLineList(model);
        // 加仓起始时间
        boolean addStartTime = false;
        // 加仓值
        List<BigDecimal> addList = new ArrayList<>();
        // 减仓起始时间
        boolean jcStartTime = false;
        // 减仓结束时间
        boolean jcEndTime = false;
        // 减仓值
        List<BigDecimal> jcList = new ArrayList<>();
        // 空数据
        Dict param = new Dict();
        // 结果集
        List<Dict> result = new ArrayList<>();
        // 遍历处理
        for (Map<String, Object> data : mapList) {
            // 提示
            String tip = data.get("tip").toString();
            // 日期
            String date = data.get("val_date").toString();
            // 值
            String val = data.get("now_val").toString();
            // 加仓处理
            if ("加仓".equals(tip) || "安全区".equals(tip)) {
                // 新的波段开始
                if (jcStartTime) {
                    // 此时需要重新刷新数据
                    jcStartTime = false;
                    addStartTime = false;
                    // 设置加仓数组
                    param.set("addList", addList);
                    // 更新加仓结束时间
                    param.set("addEndTime", param.getStr("addTime"));
                    param.set("jcList", jcList);
                    param.set("jcEndTime",param.getStr("jcTime"));
                    result.add(param);
                    param = new Dict();
                    addList = new ArrayList<>();
                    jcList = new ArrayList<>();
                }

                // 设置加仓起始时间
                if (!addStartTime) {
                    param.set("addStartTime", date);
                    addStartTime = true;
                }
                // 每次都更新记录加仓时间
                param.set("addTime", date);
                // 每次都更新记录加仓值
                param.set("addVal", val);
                // 加仓数组
                addList.add(new BigDecimal(val));
            }

            // 减仓处理
            if (("减仓".equals(tip) || "危险区".equals(tip)) && addStartTime) {
                // 设置减仓起始时间
                if (!jcStartTime) {
                    // 设置减仓起始时间
                    param.set("jcStartTime", date);
                    // 设置减仓起始时间标志
                    jcStartTime = true;
                }
                // 每次都更新记录减仓时间
                param.set("jcTime", date);
                // 每次都更新记录减仓值
                param.set("jcVal", val);
                // 减仓数组
                jcList.add(new BigDecimal(val));
            }
        }

        if (jcStartTime) {
            // 此时需要重新刷新数据
            // 设置加仓数组
            param.set("addList", addList);
            // 更新加仓结束时间
            param.set("addEndTime", param.getStr("addTime"));
            param.set("jcList", jcList);
            param.set("jcEndTime",param.getStr("jcTime"));
            result.add(param);
        }
        return result;
    }
}
